﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Xml.Linq;
using Phoenix.Xna.Framework.Properties;
using Phoenix.Xna.Framework.Xml;

namespace Phoenix.Xna.Framework.Serialization.Markup.Objects
{
    /// <summary>
    /// The intermediary markup object for IList types.
    /// </summary>
    internal class ListMarkup : ClassMarkup
    {
        /// <summary>
        /// Gets the markup for all child references in this list.
        /// </summary>
        public List<IMarkupObject> Items { get; private set; }

        /// <summary>
        /// Initializes a new instance of the ListMarkup class.
        /// </summary>
        public ListMarkup()
        {
            Items = new List<IMarkupObject>();
        }

        #region IMarkupElement Members

        /// <summary>
        /// Serialize the element to XML.
        /// </summary>
        /// <returns>The element markup serialzed as an XElement.</returns>
        public override XElement Serialize()
        {
            XElement element = base.Serialize();

            foreach (IMarkupObject child in Items)
            {
                XElement item = child.Serialize();
                item.SetAttribute(AttributeIDs.IsCollectionItemAttribute, true);
                element.Add(item);
            }

            return element;
        }

        /// <summary>
        /// Deserialzie the element from an XElement.
        /// </summary>
        /// <param name="xml">The XElement to deserialize this element from.</param>
        public override void Deserialize(XElement xml)
        {
            base.Deserialize(xml);
            XElement element = xml;

            foreach (XElement child in element.Nodes())
            {
                if (child.ReadAttribute<bool>(AttributeIDs.IsCollectionItemAttribute))
                {
                    IMarkupObject markupObject = Serializer.MarkupSelector.GetMarkupObjectFor(child);
                    Items.Add(markupObject);
                    markupObject.Deserialize(child);
                }
            }
        }

        #endregion

        #region IMarkupObject Members

        /// <summary>
        /// Convert this MarkupObject in to an object model and sets the Instance.
        /// </summary>
        public override void ConstructInstance()
        {
            base.ConstructInstance();
            IList list = (IList)Instance;

            foreach (IMarkupObject child in Items)
            {
                if (child.Instance == null)
                {
                    child.ConstructInstance();
                }

                list.Add(child.Instance);
            }
        }

        /// <summary>
        /// Extract the markup information from the specified object.
        /// </summary>
        /// <param name="instance">The instance to extract markup information for.</param>
        public override void ExtractMarkup(object instance)
        {
            base.ExtractMarkup(instance);

            if (!typeof(IList).IsAssignableFrom(instance.GetType()))
            {
                throw new InvalidCastException(string.Format(CultureInfo.InvariantCulture, Resources.InvalidCastException, instance.GetType().FullName, typeof(IList).Name));
            }

            foreach (object child in instance as IList)
            {
                IMarkupObject markupObject = Serializer.MarkupSelector.GetMarkupObjectFor(child);
                Items.Add(markupObject);
            }
        }

        #endregion
    }
}
